package site.isscloud.jt809;

import java.io.*;
import java.net.Socket;
import java.util.Calendar;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.*;

public class JT809Client {
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 19765;
    private static final int GNSS_CENTER_ID = 1001;
    private static final int HEARTBEAT_INTERVAL = 30000; // 30秒心跳间隔
    private static int msgSn = 1;
    private static volatile boolean running = true;
    
    public static void main(String[] args) {
        Socket socket = null;
        InputStream in = null;
        OutputStream out = null;
        Scanner scanner = new Scanner(System.in);
        
        System.out.print("请输入服务器IP地址(默认127.0.0.1): ");
        String serverHost = scanner.nextLine();
        if(serverHost.isEmpty()) {
            serverHost = SERVER_HOST;
        }
        
        System.out.print("请输入服务器端口号(默认19765): ");
        String portInput = scanner.nextLine();
        int serverPort = portInput.isEmpty() ? SERVER_PORT : Integer.parseInt(portInput);
        
        try {
            socket = new Socket(serverHost, serverPort);
            in = socket.getInputStream();
            out = socket.getOutputStream();
            final OutputStream finalOut = out;
            scanner = new Scanner(System.in);
            
            System.out.println("Connected to JT809 server at " + serverHost + ":" + serverPort);
            
            // 登录信息
            String userId = "test_company";
            String password = "password123";
            String downLinkIp = "127.0.0.1";
            int downLinkPort = 8001;
            
            // 发送登录请求
            LoginRequest loginRequest = new LoginRequest(userId, password, downLinkIp, downLinkPort);
            JT809Message loginMessage = new JT809Message(
                    0x1001, 
                    msgSn++, 
                    GNSS_CENTER_ID, 
                    loginRequest.toByteArray()
            );
            out.write(loginMessage.toByteArray());
            out.flush();
            System.out.println("Sent login request");
            
            // 启动心跳线程
            final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
            executor.scheduleAtFixedRate(
                new Runnable() {
                    @Override
                    public void run() {
                        sendHeartbeat(finalOut);
                    }
                }, 
                HEARTBEAT_INTERVAL, 
                HEARTBEAT_INTERVAL, 
                TimeUnit.MILLISECONDS
            );
            
            // 启动消息监听线程
            final InputStream finalIn = in;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    listenServerMessages(finalIn, executor);
                }
            }).start();
            
            // 主线程处理用户输入
            while (running) {
                // 在main方法的菜单中添加新选项
                System.out.println("\nOptions:");
                System.out.println("1. Send vehicle location");
                System.out.println("2. Send control command");
                System.out.println("3. Send vehicle static info");
                System.out.println("4. Send driver info");
                System.out.println("5. Send alarm report");
                System.out.println("6. Send vehicle operation data");
                System.out.println("7. Send company statistics info");
                System.out.println("8. Logout and exit");
                System.out.print("Enter choice: ");
                
                int choice = scanner.nextInt();
                switch (choice) {
                    case 1:
                        sendVehicleLocation(out);
                        break;
                    case 2:
                        sendVehicleControlCommand(out);
                        break;
                    case 3:
                        sendVehicleStaticInfo(out);
                        break;
                    case 4:
                        sendDriverInfo(out);
                        break;
                    case 5:
                        sendAlarmReport(out);
                        break;
                    case 6:
                        sendVehicleOperationData(out);
                        break;
                    case 7:
                        sendCompanyStatisticsInfo(out);
                        break;
                    case 8:
                        sendLogoutRequest(out);
                        running = false;
                        break;
                    default:
                        System.out.println("Invalid choice");
                }
            }
            
            executor.shutdown();
            System.out.println("Client shutdown");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (scanner != null) scanner.close();
                if (in != null) in.close();
                if (out != null) out.close();
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    private static void listenServerMessages(InputStream in, ScheduledExecutorService executor) {
        try {
            while (running) {
                JT809Message message = JT809Utils.parseJT809Message(in);
                
                if (!message.verifyCrc()) {
                    System.err.println("CRC verification failed");
                    continue;
                }
                
                System.out.println("\nReceived message from server: " + message);
                
                switch (message.getMsgId()) {
                    case 0x1002: // 登录响应
                        handleLoginResponse(message);
                        break;
                    case 0x1005: // 心跳
                        System.out.println("Received heartbeat from server");
                        break;
                    case 0x1401: // 报警处理结果
                        handleAlarmResult(message);
                        break;
                    default:
                        System.out.println("Unhandled message type: " + message.getMsgId());
                }
            }
        } catch (IOException e) {
            if (running) {
                System.err.println("Error reading from server: " + e.getMessage());
                running = false;
                executor.shutdownNow();
            }
        }
    }
    
    private static void handleLoginResponse(JT809Message message) throws IOException {
        LoginResponse loginResponse = new LoginResponse(message.getMsgBody());
        if (loginResponse.isSuccess()) {
            System.out.println("Login SUCCESS! Verify code: " + loginResponse.getVerifyCode());
        } else {
            System.out.println("Login FAILED");
            running = false;
        }
    }
    
    private static void sendHeartbeat(OutputStream out) {
        try {
            JT809Message heartbeat = new JT809Message(
                    0x1005, 
                    msgSn++, 
                    GNSS_CENTER_ID, 
                    new byte[0]
            );
            out.write(heartbeat.toByteArray());
            out.flush();
            System.out.println("Sent heartbeat to server");
        } catch (IOException e) {
            System.err.println("Failed to send heartbeat: " + e.getMessage());
            running = false;
        }
    }
    
    private static void sendLogoutRequest(OutputStream out) {
        try {
            LogoutRequest logoutRequest = new LogoutRequest("test_company");
            JT809Message logoutMessage = new JT809Message(
                    0x1003, 
                    msgSn++, 
                    GNSS_CENTER_ID, 
                    logoutRequest.toByteArray()
            );
            out.write(logoutMessage.toByteArray());
            out.flush();
            System.out.println("Sent logout request");
        } catch (IOException e) {
            System.err.println("Failed to send logout request: " + e.getMessage());
        }
    }
    
    private static void sendVehicleLocation(OutputStream out) throws IOException {
        GPSData gpsData = new GPSData(
            116, 24, (short) 60, (short) 180, System.currentTimeMillis()
        );
        
        VehicleLocationMessage location = new VehicleLocationMessage(
            "粤B12345", (byte) 0x01, gpsData, 0x00000000, 0x00000000                  
        );
        
        JT809Message locationMessage = new JT809Message(
            0x1200, msgSn++, GNSS_CENTER_ID, location.toByteArray()
        );
        
        out.write(locationMessage.toByteArray());
        out.flush();
        System.out.println("Sent vehicle location message");
    }

    private static void sendVehicleControlCommand(OutputStream out) throws IOException {
        byte commandType = 0x01;
        long startTime = System.currentTimeMillis();
        long endTime = System.currentTimeMillis() + 12*24*3600*1000L;
        int regionId = 1001;
        String[] vehicleNos = {"粤B12345", "粤A88888"};
        
        VehicleControlCommand controlCommand = new VehicleControlCommand(
            commandType, startTime, endTime, regionId, vehicleNos);
        
        JT809Message controlMessage = new JT809Message(
            0x1300, msgSn++, GNSS_CENTER_ID, controlCommand.toByteArray()
        );
        
        out.write(controlMessage.toByteArray());
        out.flush();
        System.out.println("Sent vehicle control command message");
    }
    
    private static void sendVehicleStaticInfo(OutputStream out) throws IOException {
        VehicleStaticInfo info = new VehicleStaticInfo(
            "粤B12345",          // 车牌号
            (byte) 0x01,        // 车牌颜色(1:蓝色)
            (byte) 0x02,        // 车辆类型(2:货车)
            "深圳运输有限公司",   // 所属企业
            "LSVHJ133022309876" // VIN码
        );
        
        JT809Message message = new JT809Message(
            0x1600, 
            msgSn++, 
            GNSS_CENTER_ID, 
            info.toByteArray()
        );
        
        out.write(message.toByteArray());
        out.flush();
        System.out.println("Sent vehicle static info");
    }
    
    private static void sendDriverInfo(OutputStream out) throws IOException {
        DriverInfo info = new DriverInfo(
            "张三",             // 姓名
            "440301198010101234", // 身份证号
            "GD1234567890",    // 从业资格证号
            "深圳运输有限公司"   // 所属企业
        );
        
        JT809Message message = new JT809Message(
            0x1700, 
            msgSn++, 
            GNSS_CENTER_ID, 
            info.toByteArray()
        );
        
        out.write(message.toByteArray());
        out.flush();
        System.out.println("Sent driver info");
    }

    // 发送报警信息
    private static void sendAlarmReport(OutputStream out) throws IOException {
        System.out.println("Select alarm type:");
        System.out.println("1. Over speed (超速)");
        System.out.println("2. Fatigue driving (疲劳驾驶)");
        System.out.print("Enter choice: ");
        int alarmType = 1;
        
        AlarmInfo alarmInfo = new AlarmInfo(
            "粤B12345",         // 车牌号
            (byte)0x01,        // 车牌颜色(蓝色)
            alarmType == 1 ? 0x01 : 0x02, // 报警类型
            System.currentTimeMillis(), // 报警时间
            116.404269,       // 经度
            39.915378,        // 纬度
            (short)(alarmType == 1 ? 120 : 80), // 速度(km/h)
            (short)180,        // 方向
            0,                // 状态(未处理)
            alarmType == 1 ? "车辆超速行驶" : "驾驶员疲劳驾驶" // 报警描述
        );
        
        JT809Message message = new JT809Message(
            0x1400,
            msgSn++,
            GNSS_CENTER_ID,
            alarmInfo.toByteArray()
        );
        
        out.write(message.toByteArray());
        out.flush();
        System.out.println("Sent alarm report: " + alarmInfo);
    }

    // 处理报警结果
    private static void handleAlarmResult(JT809Message message) throws IOException {
        AlarmResult result = AlarmResult.fromByteArray(message.getMsgBody());
        System.out.println("Received alarm result from server:");
        System.out.println("Vehicle: " + result.getVehicleNo());
        System.out.println("Alarm Type: " + (result.getAlarmType() == 0x01 ? "Over speed" : "Fatigue driving"));
        System.out.println("Result: " + (result.getResultType() == 0x01 ? "Warning" : "Penalty"));
        System.out.println("Description: " + result.getResultDesc());
    }

    // 添加新的发送方法
    private static void sendVehicleOperationData(OutputStream out) throws IOException {
        Random random = new Random();
        String[] samplePlates = {"粤B12345", "粤A88888", "京C56789", "沪D24680"};
        
        // 随机选择一辆车
        String vehicleNo = samplePlates[random.nextInt(samplePlates.length)];
        byte vehicleColor = (byte)(0x01 + random.nextInt(5)); // 随机车牌颜色(1-5)
        
        // 生成当前日期和随机历史日期(YYMMDD格式)
        Calendar cal = Calendar.getInstance();
        int year = cal.get(Calendar.YEAR) % 100; // 取后两位
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        String today = String.format("%02d%02d%02d", year, month, day);
        
        // 模拟月度统计数据
        byte periodType = 0x02; // 月度统计
        String monthStart = String.format("%02d%02d01", year, month);
        String monthEnd = today; // 当月至今
        
        VehicleOperationData monthData = new VehicleOperationData(
            vehicleNo,
            vehicleColor,
            periodType,
            monthStart,
            monthEnd,
            3000 + random.nextInt(4000),  // 月里程3000-7000km
            random.nextInt(5),             // 月违规0-4次
            800 + random.nextInt(500)      // 月油耗800-1300升
        );
        
        JT809Message monthMessage = new JT809Message(
            0x1800,
            msgSn++,
            GNSS_CENTER_ID,
            monthData.toByteArray()
        );
        out.write(monthMessage.toByteArray());
        out.flush();
        System.out.println("Sent monthly operation data: " + monthData);
        
        // 模拟当日统计数据
        periodType = 0x01; // 日统计
        VehicleOperationData dailyData = new VehicleOperationData(
            vehicleNo,
            vehicleColor,
            periodType,
            today,
            today,
            100 + random.nextInt(150),  // 日里程100-250km
            random.nextInt(2),          // 日违规0-1次
            30 + random.nextInt(30)     // 日油耗30-60升
        );
        
        JT809Message dailyMessage = new JT809Message(
            0x1800,
            msgSn++,
            GNSS_CENTER_ID,
            dailyData.toByteArray()
        );
        out.write(dailyMessage.toByteArray());
        out.flush();
        System.out.println("Sent daily operation data: " + dailyData);
        
        // 30%概率发送历史月份数据
        if (random.nextDouble() < 0.3) {
            int histMonth = month - 1;
            int histYear = year;
            if (histMonth < 1) {
                histMonth = 12;
                histYear--;
            }
            
            String histStart = String.format("%02d%02d01", histYear, histMonth);
            String histEnd = String.format("%02d%02d%02d", histYear, histMonth, 
                histMonth == 2 ? 28 : 30); // 简化处理每月天数
            
            VehicleOperationData histData = new VehicleOperationData(
                vehicleNo,
                vehicleColor,
                (byte)0x02, // 月度统计
                histStart,
                histEnd,
                3500 + random.nextInt(3000),  // 历史月里程3500-6500km
                random.nextInt(4),             // 历史月违规0-3次
                850 + random.nextInt(400)      // 历史月油耗850-1250升
            );
            
            JT809Message histMessage = new JT809Message(
                0x1800,
                msgSn++,
                GNSS_CENTER_ID,
                histData.toByteArray()
            );
            out.write(histMessage.toByteArray());
            out.flush();
            System.out.println("Sent historical monthly data: " + histData);
        }
    }

    private static void sendCompanyStatisticsInfo(OutputStream out) throws IOException {
        Random random = new Random();
        
        // 获取当前日期(YYMMDD格式)
        Calendar cal = Calendar.getInstance();
        int year = cal.get(Calendar.YEAR) % 100;
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        String currentDate = String.format("%02d%02d%02d", year, month, day);
        
        // 模拟不同运输公司数据
        String[] companyIds = {"TRAN001", "LOGIS002", "EXPRS003"};
        String[] companyNames = {
            "深圳运输有限公司", 
            "广州物流集团", 
            "华东快递服务公司"
        };
        
        // 随机选择一家公司
        int index = random.nextInt(companyIds.length);
        String companyId = companyIds[index];
        String companyName = companyNames[index];
        
        // 生成模拟统计数据
        int totalVehicles = 100 + random.nextInt(200);  // 100-300辆车
        int onlineVehicles = (int)(totalVehicles * (0.7 + random.nextDouble() * 0.2)); // 70-90%在线率
        int totalDrivers = (int)(totalVehicles * (1.0 + random.nextDouble() * 0.5));  // 1-1.5倍驾驶员
        float complianceRate = 0.8f + random.nextFloat() * 0.15f; // 80-95%合规率
        
        // 创建公司统计信息对象
        CompanyStatisticsInfo info = new CompanyStatisticsInfo(
            companyId,
            companyName + "(" + currentDate + "统计)", // 在名称中加入统计日期
            totalVehicles,
            onlineVehicles,
            totalDrivers,
            complianceRate
        );
        
        // 创建并发送JT809消息
        JT809Message message = new JT809Message(
            0x1900,
            msgSn++,
            GNSS_CENTER_ID,
            info.toByteArray()
        );
        
        out.write(message.toByteArray());
        out.flush();
        System.out.println("Sent company statistics info: " + info);
        
        // 30%概率发送分公司数据
        if (random.nextDouble() < 0.3) {
            String branchId = companyId + "-B" + (random.nextInt(5) + 1);
            String branchName = companyName + "第" + (random.nextInt(5) + 1) + "分公司";
            
            int branchVehicles = 20 + random.nextInt(50); // 20-70辆车
            int branchOnline = (int)(branchVehicles * (0.6 + random.nextDouble() * 0.3)); // 60-90%在线率
            
            CompanyStatisticsInfo branchInfo = new CompanyStatisticsInfo(
                branchId,
                branchName,
                branchVehicles,
                branchOnline,
                (int)(branchVehicles * (0.8 + random.nextDouble() * 0.4)), // 0.8-1.2倍驾驶员
                0.85f + random.nextFloat() * 0.1f // 85-95%合规率
            );
            
            JT809Message branchMessage = new JT809Message(
                0x1900,
                msgSn++,
                GNSS_CENTER_ID,
                branchInfo.toByteArray()
            );
            
            out.write(branchMessage.toByteArray());
            out.flush();
            System.out.println("Sent branch company statistics: " + branchInfo);
        }
    }
}
